﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using MEF_Test.Bricks;
using MEF_Test.Bricks.Actions;
using MEF_Test.Contracts;
using MEF_Test.Module.AudioStation.Tests.Properties;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Synology.AudioStationApi;

namespace MEF_Test.Module.AudioStation.Tests
{
    /// <summary>
    /// Summary description for AudioStationBrowsingProviderTest
    /// </summary>
    [TestClass]
    public class AudioStationBrowsingProviderTest
    {
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestInitialize]
        public void  IoCInitialize()
        {
            var actionManagerMock = new Mock<IActionsManager>();
            actionManagerMock.Setup(o => o.ExportedActions).Returns(
                new ObservableCollection<Lazy<INodeAction, IDictionary<string, object>>>());
            IoC.Current.RegisterInstance(actionManagerMock.Object);
        }

        [TestMethod]
        public void CategoryBrowserNodeFactoryTest()
        {

            var category1 = new SynoItem
                {
                    Sequence = 0,
                    IsContainer = true,
                    ItemID = "musiclib_music_all",
                    ItemPid = "musiclib",
                    IsTrack = false,
                    Title = "Toute la musique"
                };
            var browserNode = BrowserNodeFactory.CreateBrowserNode(category1);
            Assert.AreEqual(browserNode.Caption, category1.Title);
            Assert.AreEqual(browserNode.FileHandler.CanHaveChildren, category1.IsContainer);
            Assert.AreEqual(browserNode.FileHandler.ItemID, category1.ItemID);
        }

        [TestMethod]
        public void CategoryBrowserNodeCollectionFactoryTest()
        {
            // Init Categories
            var categories = new List<SynoItem>();
            categories.Add(new SynoItem { Sequence = 0, IsContainer = true, ItemID = "musiclib_music_all", ItemPid = "musiclib", IsTrack = false, Title = "Toute la musique" });
            categories.Add(new SynoItem { Sequence = 1, IsContainer = true, ItemID = "musiclib_music_file", ItemPid = "musiclib", IsTrack = false, Title = "Par dossier" });
            categories.Add(new SynoItem { Sequence = 2, IsContainer = true, ItemID = "musiclib_music_album", ItemPid = "musiclib", IsTrack = false, Title = "Par album" });
            categories.Add(new SynoItem { Sequence = 3, IsContainer = true, ItemID = "musiclib_music_aa", ItemPid = "musiclib", IsTrack = false, Title = "Par artiste" });
            categories.Add(new SynoItem { Sequence = 4, IsContainer = true, ItemID = "musiclib_music_genre", ItemPid = "musiclib", IsTrack = false, Title = "Par genre" });
            categories.Add(new SynoItem { Sequence = 5, IsContainer = true, ItemID = "musiclib_random", ItemPid = "musiclib", IsTrack = false, Title = "Random 100" });
            List<BrowserNodeViewModel<AudioStationFileHandler>> browserNodes = new List<BrowserNodeViewModel<AudioStationFileHandler>>(categories.Count);
            foreach (var category in categories)
            {
                browserNodes.Add(BrowserNodeFactory.CreateBrowserNode(category));
            }

            foreach (var category in categories)
            {
                // Every element is present in the browserNodes, and they're ordered.
                Assert.AreEqual(category.Title, browserNodes[category.Sequence].Caption);
            }


        }

        [TestMethod]
        public void CreateAudioStationBrowsingProvider()
        {
            // Mock AudioStationApi
            var apiMock = new Mock<IAudioStationSession>();
            apiMock.Setup(o=>o.Login("login","password")).Returns("id=123456");

            Assert.Inconclusive("Search (synchronous) is not implemented yet.");
            // Setup the mock to return a collection of Albums (Categories) on a Search method-call.
            apiMock.Setup(o => o.Search());

            // use IoC to register a mocked API.            
            IoC.Current.RegisterInstance(typeof(IAudioStationSession),apiMock.Object);
            

            // Create FileHandler for AudioRoot.
            var fh = new AudioStationFileHandler(AudioStationAction.Browse, new SynoItem { ItemID = "musiclib_root" });

            // Wrap in a BrowserNode
            var bn = new BrowserNodeViewModel<AudioStationFileHandler>(fh);
            
            // pass it to a new instance of AudioStationBrowsingProvider (in .ctor)
            AudioStationBrowsingProvider browsingProvider = new AudioStationBrowsingProvider(bn, Settings.Default.SynoHost,Settings.Default.SynoPort);

            browsingProvider.CurrentChildrenChanged += (o, e) =>
                                                           {
                                                               Assert.IsFalse(e.Children.Count() == 0);
                                                           };
            
            browsingProvider.GoToNode(bn);



            // make sure the children of the current node are the same as those returned by the Mock API.            
            Assert.Inconclusive("Not Implemented Yet");
        }
    }

    public static class BrowserNodeFactory
    {
        
        public static BrowserNodeViewModel<AudioStationFileHandler> CreateBrowserNode<T>(T item) where T : SynoItem
        {
            if (typeof(T).IsAssignableFrom(typeof(SynoItem)))
            {
                var fh = new AudioStationFileHandler(AudioStationAction.Browse, item);
                var bn = new BrowserNodeViewModel<AudioStationFileHandler>(fh) { Caption = item.Title };                
                return bn;
            }
            throw new NotImplementedException();
        }
    }
}
